package luke.media.video;

import java.awt.*;
import java.awt.RadialGradientPaint;
import java.util.List;

import java.util.Random;


/**
 * 视频UI工具类，用于统一处理视频生成器中的公共UI元素绘制
 */
public class VideoUIUtils {
    
    /**
     * 统一的播放列表绘制方法
     * @param g2d Graphics2D对象
     * @param playlistContent 播放列表内容
     * @param width 视频宽度
     * @param height 视频高度
     * @param videoTitle 视频标题
     */
    public static void drawPlaylist(Graphics2D g2d, List<String> playlistContent, int width, int height, String videoTitle) {
        // 根据横竖屏调整播放列表的列数和大小
        boolean isLandscape = width > height;
        
        // 统一播放列表框的尺寸，增加高度以提供更多空间
        int playlistWidth = isLandscape ? (int)(width * 0.7) : (int)(width * 0.8);
        int playlistHeight = isLandscape ? (int)(height * 0.8) : (int)(height * 0.7); // 增加高度
        int playlistX = (width - playlistWidth) / 2; // 居中显示
        int playlistY = (height - playlistHeight) / 2; // 居中显示
        
        // 绘制半透明背景，根据用户偏好设置透明度为120（约47%不透明）
        g2d.setColor(new Color(0, 0, 0, 120));
        g2d.fillRoundRect(playlistX, playlistY, playlistWidth, playlistHeight, 20, 20);
        
        // 绘制统一的蓝紫色边框
        g2d.setColor(new Color(100, 150, 255));
        g2d.setStroke(new BasicStroke(3));
        g2d.drawRoundRect(playlistX, playlistY, playlistWidth, playlistHeight, 20, 20);
        
        // 绘制标题
        g2d.setFont(new Font("SimHei", Font.BOLD, 36));
        g2d.setColor(new Color(100, 200, 255));
        FontMetrics fm = g2d.getFontMetrics();
        int titleWidth = fm.stringWidth(videoTitle);
        g2d.drawString(videoTitle, playlistX + (playlistWidth - titleWidth) / 2, playlistY + 50);
        
        // 绘制装饰线，调整位置使其与标题保持适当距离
        g2d.setColor(new Color(100, 150, 255));
        int lineY = playlistY + 65; // 恢复原来的装饰线位置
        g2d.setStroke(new BasicStroke(2));
        g2d.drawLine(playlistX + 30, lineY, playlistX + playlistWidth - 30, lineY);
        
        // 绘制歌曲列表
        // 计算自适应字体大小和布局，根据用户偏好调整字体大小范围（最小18-最大32）
        int maxFontSize = 32;
        int minFontSize = 16; // 恢复原来的最小字体大小
        
        // 如果是横屏两列显示
        if (isLandscape) {
            // 计算每列的宽度
            int columnWidth = (playlistWidth - 80) / 2;
            
            // 自适应字体大小，确保文字能适应宽度和高度
            int fontSize = maxFontSize;
            g2d.setFont(new Font("SimHei", Font.PLAIN, fontSize));
            fm = g2d.getFontMetrics();
            
            // 找到适合最长文字的字体大小
            if (!playlistContent.isEmpty()) {
                String longestLine = playlistContent.get(0);
                for (String line : playlistContent) {
                    if (line.length() > longestLine.length()) {
                        longestLine = line;
                    }
                }
                
                // 先适应宽度
                while (fm.stringWidth(longestLine) > columnWidth - 20 && fontSize > minFontSize) {
                    fontSize--;
                    g2d.setFont(new Font("SimHei", Font.PLAIN, fontSize));
                    fm = g2d.getFontMetrics();
                }
            }
            
            int lineHeight = fm.getHeight();
            int lineSpacing = 5; // 行间距
            
            // 计算可显示的行数
            int availableHeight = playlistHeight - 140; // 调整回140，保持合适的间距
            int maxLines = availableHeight / (lineHeight + lineSpacing);
            
            // 如果内容太多，需要进一步减小字体大小以适应高度
            if (!playlistContent.isEmpty() && maxLines < playlistContent.size()) {
                // 重新计算字体大小以适应高度
                int requiredLines = playlistContent.size();
                int itemsPerColumn = (requiredLines + 1) / 2; // 每列的项目数
                
                // 计算需要的行高
                int requiredHeight = itemsPerColumn * (lineHeight + lineSpacing);
                
                // 如果需要的高度超过了可用高度，则减小字体大小
                while (requiredHeight > availableHeight && fontSize > minFontSize) {
                    fontSize--;
                    g2d.setFont(new Font("SimHei", Font.PLAIN, fontSize));
                    fm = g2d.getFontMetrics();
                    lineHeight = fm.getHeight();
                    requiredHeight = itemsPerColumn * (lineHeight + lineSpacing);
                }
                
                // 重新计算最大行数
                maxLines = availableHeight / (lineHeight + lineSpacing);
            }
            
            int startY = playlistY + 100; // 调整回100，保持合适的间距
            
            // 绘制播放列表内容
            int itemsPerColumn = (maxLines + 1) / 2; // 每列的项目数
            for (int i = 0; i < Math.min(playlistContent.size(), maxLines * 2); i++) { // 允许显示两列的内容
                String line = playlistContent.get(i);
                
                // 确定当前项目应该放在哪一列
                int columnIndex = i / itemsPerColumn;
                int rowIndex = i % itemsPerColumn;
                
                // 如果超出了两列的容量，只显示第一列
                if (columnIndex >= 2) {
                    break;
                }
                
                // 计算X位置
                int column1X = playlistX + 30;
                int column2X = playlistX + 30 + columnWidth + 20;
                int itemX = (columnIndex == 0) ? column1X : column2X;
                
                // 如果文本过长则截断并添加省略号，为文字留出足够空间
                if (fm.stringWidth(line) > columnWidth - 20) {
                    line = truncateText(line, fm, columnWidth - 20);
                }
                
                // 绘制文本（移除交替背景色绘制）
                g2d.setColor(Color.WHITE);
                // 使用正确的Y坐标计算方式
                int textY = startY + rowIndex * (lineHeight + lineSpacing) + fm.getAscent();
                g2d.drawString(line, itemX, textY);
            }
        } else {
            // 竖屏单列显示
            // 自适应字体大小，确保文字能适应宽度和高度
            int fontSize = maxFontSize;
            g2d.setFont(new Font("SimHei", Font.PLAIN, fontSize));
            fm = g2d.getFontMetrics();
            
            // 找到适合最长文字的字体大小
            if (!playlistContent.isEmpty()) {
                String longestLine = playlistContent.get(0);
                for (String line : playlistContent) {
                    if (line.length() > longestLine.length()) {
                        longestLine = line;
                    }
                }
                
                // 先适应宽度
                while (fm.stringWidth(longestLine) > playlistWidth - 60 && fontSize > minFontSize) {
                    fontSize--;
                    g2d.setFont(new Font("SimHei", Font.PLAIN, fontSize));
                    fm = g2d.getFontMetrics();
                }
            }
            
            int lineHeight = fm.getHeight();
            int lineSpacing = 5; // 行间距
            
            // 计算可显示的行数
            int availableHeight = playlistHeight - 140; // 调整回140，保持合适的间距
            int maxLines = availableHeight / (lineHeight + lineSpacing);
            
            // 如果内容太多，需要进一步减小字体大小以适应高度
            if (!playlistContent.isEmpty() && maxLines < playlistContent.size()) {
                // 重新计算字体大小以适应高度
                int requiredLines = playlistContent.size();
                
                // 计算需要的行高
                int requiredHeight = requiredLines * (lineHeight + lineSpacing);
                
                // 如果需要的高度超过了可用高度，则减小字体大小
                while (requiredHeight > availableHeight && fontSize > minFontSize) {
                    fontSize--;
                    g2d.setFont(new Font("SimHei", Font.PLAIN, fontSize));
                    fm = g2d.getFontMetrics();
                    lineHeight = fm.getHeight();
                    requiredHeight = requiredLines * (lineHeight + lineSpacing);
                }
                
                // 重新计算最大行数
                maxLines = availableHeight / (lineHeight + lineSpacing);
            }
            
            int startY = playlistY + 100; // 调整回100，保持合适的间距
            
            // 绘制播放列表内容
            for (int i = 0; i < Math.min(playlistContent.size(), maxLines); i++) {
                String line = playlistContent.get(i);
                
                // 如果文本过长则截断并添加省略号，为文字留出足够空间
                if (fm.stringWidth(line) > playlistWidth - 60) {
                    line = truncateText(line, fm, playlistWidth - 60);
                }
                
                // 绘制文本（移除交替背景色绘制）
                g2d.setColor(Color.WHITE);
                // 使用正确的Y坐标计算方式
                int textY = startY + i * (lineHeight + lineSpacing) + fm.getAscent();
                g2d.drawString(line, playlistX + 30, textY);
            }
        }
        // 重置裁剪区域
        g2d.setClip(null);
    }
    
    /**
     * 截断文本并在末尾添加省略号
     * @param text 原始文本
     * @param fm 字体度量
     * @param maxWidth 最大宽度
     * @return 截断后的文本
     */
    public static String truncateText(String text, FontMetrics fm, int maxWidth) {
        if (fm.stringWidth(text) <= maxWidth) {
            return text;
        }
        
        String suffix = "...";
        int suffixWidth = fm.stringWidth(suffix);
        
        if (maxWidth <= suffixWidth) {
            // 如果最大宽度甚至不足以容纳省略号，则返回省略号
            return suffix;
        }
        
        int availableWidth = maxWidth - suffixWidth;
        
        // 逐步缩短文本直到适合宽度
        String truncated = text;
        while (fm.stringWidth(truncated) > availableWidth && truncated.length() > 0) {
            truncated = truncated.substring(0, truncated.length() - 1);
        }
        
        return truncated + suffix;
    }
    
    /**
     * 统一的时间信息绘制方法
     * @param g2d Graphics2D对象
     * @param currentTime 当前时间（秒）
     * @param width 视频宽度
     * @param height 视频高度
     */
    public static void drawTimeInfo(Graphics2D g2d, double currentTime, int width, int height) {
        // 格式化时间显示
        int minutes = (int) (currentTime / 60);
        int seconds = (int) (currentTime % 60);
        String timeString = String.format("时间: %02d:%02d", minutes, seconds);
        
        // 绘制时间信息背景
        g2d.setFont(new Font("SimHei", Font.BOLD, 24));
        FontMetrics fm = g2d.getFontMetrics();
        int timeWidth = fm.stringWidth(timeString);
        int timeHeight = fm.getHeight();
        
        // 绘制半透明背景
        g2d.setColor(new Color(0, 0, 0, 180));
        g2d.fillRoundRect(width - timeWidth - 30, 35, timeWidth + 20, timeHeight + 10, 10, 10);
        
        // 绘制边框
        g2d.setColor(new Color(100, 100, 255));
        g2d.setStroke(new BasicStroke(1));
        g2d.drawRoundRect(width - timeWidth - 30, 35, timeWidth + 20, timeHeight + 10, 10, 10);
        
        // 绘制时间文本
        g2d.setColor(Color.WHITE);
        g2d.drawString(timeString, width - timeWidth - 20, 35 + fm.getAscent() + 5);
    }
    
    /**
     * 统一的边框颜色生成方法
     * @param baseColor 基础颜色
     * @return 边框颜色
     */
    public static Color getBorderColor(Color baseColor) {
        int red = Math.max(0, baseColor.getRed() - 30);
        int green = Math.max(0, baseColor.getGreen() - 30);
        int blue = Math.max(0, baseColor.getBlue() - 30);
        return new Color(red, green, blue);
    }
    
    /**
     * 统一的高光颜色生成方法
     * @param baseColor 基础颜色
     * @return 高光颜色
     */
    public static Color getHighlightColor(Color baseColor) {
        int red = Math.min(255, baseColor.getRed() + 50);
        int green = Math.min(255, baseColor.getGreen() + 50);
        int blue = Math.min(255, baseColor.getBlue() + 50);
        return new Color(red, green, blue);
    }
    
    /**
     * 统一的蓝紫色渐变颜色生成方法
     * @param frequencyRatio 频率比例（0.0-1.0）
     * @return 对应的蓝紫色渐变颜色
     */
    public static Color getBluePurpleColor(float frequencyRatio) {
        // 优化的蓝紫色渐变：从深蓝到紫色到洋红
        // 使用更平滑的颜色过渡
        
        // 将频率比例映射到0-255的范围
        int colorValue = (int) (frequencyRatio * 255);
        
        int red, green, blue;
        
        if (colorValue < 85) {
            // 从深蓝(0,0,128)到蓝色(0,0,255)
            red = 0;
            green = 0;
            blue = 128 + colorValue * 3 / 2;
        } else if (colorValue < 170) {
            // 从蓝色(0,0,255)到紫色(128,0,255)
            red = (colorValue - 85) * 3 / 2;
            green = 0;
            blue = 255;
        } else {
            // 从紫色(128,0,255)到洋红(255,0,255)
            red = 128 + (colorValue - 170) * 127 / 85;  // 平滑过渡到255
            green = 0;
            blue = 255 - (colorValue - 170) * 127 / 85; // 平滑过渡到128
        }
        
        // 添加一些亮度变化使颜色更生动，增强高频部分亮度
        float brightness = 0.9f + 0.5f * (float) Math.sin(frequencyRatio * Math.PI * 2);
        red = Math.min(255, (int) (red * brightness));
        green = Math.min(255, (int) (green * brightness));
        blue = Math.min(255, (int) (blue * brightness));
        
        return new Color(red, green, blue);
    }
    
    /**
     * 统一的动态星星粒子类（基于周期性函数的实现）
     */
    public static class StarParticle {
        // 固定属性，用于周期性函数计算
        long seed;             // 粒子的固定随机种子
        float size;            // 粒子大小
        float blinkSpeed;      // 闪烁速度
        Color color;           // 颜色
        float baseAlpha;       // 基础透明度
        float baseBrightness;  // 基础亮度
        float startX, startY;  // 初始位置
        float velocityX, velocityY; // 速度向量
        int maxLifetime;       // 最大生命周期
        int creationFrame;     // 创建帧索引

        public StarParticle(int width, int height, Random random, int frameIndex) {
            // 使用固定种子确保粒子属性的一致性
            this.seed = random.nextLong();
            Random seededRandom = new Random(seed);
            
            // 随机初始位置（在屏幕底部附近），但限制X轴变化范围以形成更连贯的轨迹
            this.startX = width/2 + (seededRandom.nextInt(width/2) - width/4); // 从屏幕中间区域开始
            this.startY = height - 30 + seededRandom.nextInt(60); // 减小Y轴变化范围

            // 更平滑的速度，减小随机性以形成更连贯的轨迹
            this.velocityX = (seededRandom.nextFloat() - 0.5f) * 1.0f; // 减小水平速度范围
            this.velocityY = - (1.5f + seededRandom.nextFloat() * 1.5f); // 减小垂直速度范围，使运动更平滑

            // 更一致的大小和亮度
            this.size = 1.5f + seededRandom.nextFloat() * 2.0f; // 减小大小变化范围
            this.baseBrightness = 0.6f + seededRandom.nextFloat() * 0.4f; // 减小亮度变化范围

            // 随机颜色（蓝色和紫色之间）
            if (seededRandom.nextBoolean()) {
                // 偏蓝 (R:100-200,G:150-250,B:200-255)
                int red = 100 + seededRandom.nextInt(101);
                int green = 150 + seededRandom.nextInt(101);
                int blue = 200 + seededRandom.nextInt(56);
                color = new Color(red, green, blue);
            } else {
                // 偏紫 (R:150-250,G:100-200,B:200-255)
                int red = 150 + seededRandom.nextInt(101);
                int green = 100 + seededRandom.nextInt(101);
                int blue = 200 + seededRandom.nextInt(56);
                color = new Color(red, green, blue);
            }

            // 降低整体亮度以避免刺眼
            color = new Color(
                (int) (color.getRed() * 0.7),
                (int) (color.getGreen() * 0.7),
                (int) (color.getBlue() * 0.7)
            );

            // 更一致的生命周期
            this.maxLifetime = 40 + seededRandom.nextInt(30); // 增加最小生命周期，使星星存在更长时间
            this.creationFrame = frameIndex; // 记录创建帧索引
            
            // 其他属性
            this.blinkSpeed = 0.01f + seededRandom.nextFloat() * 0.02f;
            this.baseAlpha = seededRandom.nextFloat() * 0.6f + 0.2f; // 降低初始透明度
        }
        
        /**
         * 根据帧索引计算粒子的当前状态
         * @param width 视频宽度
         * @param height 视频高度
         * @param frameIndex 当前帧索引
         * @return 粒子是否仍然存活
         */
        public boolean update(int width, int height, int frameIndex) {
            // 计算粒子的生命周期
            int age = frameIndex - creationFrame;
            if (age < 0 || age > maxLifetime) {
                return false; // 粒子已死亡
            }
            return true; // 粒子仍然存活
        }
        
        /**
         * 根据帧索引计算粒子的位置
         * @param width 视频宽度
         * @param height 视频高度
         * @param frameIndex 当前帧索引
         * @return 粒子的当前位置
         */
        public Point2D getPosition(int width, int height, int frameIndex) {
            int age = frameIndex - creationFrame;
            if (age < 0) age = 0;
            if (age > maxLifetime) age = maxLifetime;
            
            // 根据初始位置和速度计算当前位置
            double x = startX + velocityX * age;
            double y = startY + velocityY * age;
            
            // 边界检查 - 当星星移出屏幕时，从另一边出现
            if (x < -size * 4) x = width + size * 4;
            if (x > width + size * 4) x = -size * 4;
            if (y < -size * 4) y = height + size * 4;
            if (y > height + size * 4) y = -size * 4;
            
            return new Point2D(x, y);
        }
        
        /**
         * 根据帧索引计算粒子的当前大小
         * @param frameIndex 当前帧索引
         * @return 粒子的当前大小
         */
        public float getCurrentSize(int frameIndex) {
            int age = frameIndex - creationFrame;
            if (age < 0) age = 0;
            if (age > maxLifetime) age = maxLifetime;
            
            // 随着生命周期减少，星星逐渐变小
            float lifeRatio = 1.0f - (float) age / maxLifetime;
            return size * lifeRatio;
        }
        
        /**
         * 根据帧索引计算粒子的当前透明度
         * @param frameIndex 当前帧索引
         * @return 粒子的当前透明度
         */
        public float getCurrentAlpha(int frameIndex) {
            int age = frameIndex - creationFrame;
            if (age < 0) age = 0;
            if (age > maxLifetime) age = maxLifetime;
            
            // 随着生命周期减少，透明度逐渐降低
            float lifeRatio = 1.0f - (float) age / maxLifetime;
            return baseAlpha * lifeRatio;
        }
        
        /**
         * 根据帧索引计算粒子的当前亮度
         * @param frameIndex 当前帧索引
         * @return 粒子的当前亮度
         */
        public float getCurrentBrightness(int frameIndex) {
            int age = frameIndex - creationFrame;
            if (age < 0) age = 0;
            if (age > maxLifetime) age = maxLifetime;
            
            // 闪烁效果
            double time = age / 30.0; // 假设30fps
            float blinkEffect = 0.6f + 0.2f * (float) Math.sin(time * blinkSpeed * 10);
            return baseBrightness * blinkEffect;
        }
        
        public void draw(Graphics2D g2d, int width, int height, int frameIndex) {
            // 检查粒子是否存活
            if (!update(width, height, frameIndex)) {
                return;
            }
            
            // 获取粒子的当前状态
            Point2D position = getPosition(width, height, frameIndex);
            float currentSize = getCurrentSize(frameIndex);
            float currentAlpha = getCurrentAlpha(frameIndex);
            float currentBrightness = getCurrentBrightness(frameIndex);
            
            // 星星的核心亮度
            float coreBrightness = currentBrightness * currentAlpha;
            
            // 只有当星星足够大时才绘制光晕
            if (currentSize > 0.5f) {
                // 绘制多层光晕，从内到外逐渐变暗
                // 第一层光晕（最亮）
                float[] fractions1 = {0.0f, 1.0f};
                Color[] colors1 = {
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(100 * coreBrightness)), // 降低亮度
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), 0)
                };
                
                RadialGradientPaint gradient1 = new RadialGradientPaint(
                    (float)position.x, (float)position.y, currentSize * 1.5f,
                    fractions1, colors1
                );
                
                g2d.setPaint(gradient1);
                g2d.fillOval((int)(position.x - currentSize * 1.5f), (int)(position.y - currentSize * 1.5f), (int)(currentSize * 3), (int)(currentSize * 3));
                
                // 第二层光晕（中等亮度）
                float[] fractions2 = {0.0f, 1.0f};
                Color[] colors2 = {
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(60 * coreBrightness)), // 降低亮度
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), 0)
                };
                
                RadialGradientPaint gradient2 = new RadialGradientPaint(
                    (float)position.x, (float)position.y, currentSize * 3.0f,
                    fractions2, colors2
                );
                
                g2d.setPaint(gradient2);
                g2d.fillOval((int)(position.x - currentSize * 3.0f), (int)(position.y - currentSize * 3.0f), (int)(currentSize * 6), (int)(currentSize * 6));
                
                // 第三层光晕（最暗）
                float[] fractions3 = {0.0f, 1.0f};
                Color[] colors3 = {
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(30 * coreBrightness)), // 降低亮度
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), 0)
                };
                
                RadialGradientPaint gradient3 = new RadialGradientPaint(
                    (float)position.x, (float)position.y, currentSize * 5.0f,
                    fractions3, colors3
                );
                
                g2d.setPaint(gradient3);
                g2d.fillOval((int)(position.x - currentSize * 5.0f), (int)(position.y - currentSize * 5.0f), (int)(currentSize * 10), (int)(currentSize * 10));
            }
            
            // 绘制星星核心（使用更柔和的颜色）
            g2d.setColor(new Color(
                Math.min(255, color.getRed() + 50),
                Math.min(255, color.getGreen() + 50),
                Math.min(255, color.getBlue() + 50),
                (int)(200 * coreBrightness)
            ));
            g2d.fillOval((int)(position.x - currentSize * 0.5f), (int)(position.y - currentSize * 0.5f), (int)(currentSize), (int)(currentSize));
        }
    }
    
    // Point2D类用于表示二维点
    public static class Point2D {
        public double x, y;
        
        public Point2D(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }
    
    /**
     * 统一的星空背景绘制方法
     * @param g2d Graphics2D对象
     * @param width 视频宽度
     * @param height 视频高度
     * @param frameIndex 帧索引
     */
    public static void drawStarfieldBackground(Graphics2D g2d, int width, int height, int frameIndex) {
        // 创建深蓝色到黑色的渐变背景
        GradientPaint gradient = new GradientPaint(
                0, 0, new Color(10, 5, 30),
                0, height, new Color(0, 0, 10)
        );
        g2d.setPaint(gradient);
        g2d.fillRect(0, 0, width, height);

        // 使用固定种子的随机数生成器，确保每次调用的一致性
        Random rand = new Random(0); // 使用固定种子确保背景星星的一致性
        
        // 绘制背景星星（固定位置的星星）
        for (int i = 0; i < 200; i++) {
            // 使用固定的随机种子计算星星位置
            long starSeed = rand.nextLong();
            Random starRand = new Random(starSeed);
            
            // 计算星星位置
            int x = starRand.nextInt(width);
            int y = starRand.nextInt(height);
            float size = 0.5f + starRand.nextFloat() * 1.5f;
            float alpha = 0.2f + starRand.nextFloat() * 0.3f;
            
            // 随机颜色（在蓝色和紫色之间）
            int r, g, b;
            double colorChoice = starRand.nextDouble();
            if (colorChoice < 0.5) {
                // 蓝色系 (偏蓝)
                r = 100 + starRand.nextInt(100);
                g = 150 + starRand.nextInt(100);
                b = 200 + starRand.nextInt(55);
            } else {
                // 紫色系 (偏紫)
                r = 150 + starRand.nextInt(100);
                g = 100 + starRand.nextInt(100);
                b = 200 + starRand.nextInt(55);
            }
            Color color = new Color(r, g, b);
            
            // 绘制星星
            g2d.setColor(new Color(
                color.getRed(), 
                color.getGreen(), 
                color.getBlue(), 
                (int)(255 * alpha)
            ));
            g2d.fillOval(x, y, (int)size, (int)size);
        }
    }
    
    /**
     * 统一的动态星星粒子绘制方法（基于周期性函数的实现）
     * @param g2d Graphics2D对象
     * @param width 视频宽度
     * @param height 视频高度
     * @param frameIndex 帧索引
     * @param globalFrameIndex 全局帧索引（用于分段视频处理）
     * @param random 随机数生成器
     */
    public static void drawStarParticles(Graphics2D g2d, int width, int height, int frameIndex, int globalFrameIndex, Random random) {
        // 使用周期性函数生成星星粒子，所有随机属性都是预先定义好的固定值
        // 每一帧都根据固定的随机种子和帧索引重新计算所有星星的状态
        
        // 固定的星星数量
        int starCount = 600;
        
        // 为每一颗星星计算状态并绘制
        for (int i = 0; i < starCount; i++) {
            // 使用固定的种子计算星星属性（这些属性是预先定义好的固定值）
            long starSeed = (long) i * 987654321L;
            Random starRand = new Random(starSeed);
            
            // 预先定义好的固定随机属性
            float startX = starRand.nextFloat() * width; // 随机的出生位置X
            float startY = starRand.nextFloat() * height; // 随机的出生位置Y
            float velocityX = (starRand.nextFloat() - 0.5f) * 4.0f; // 随机的速度X
            float velocityY = (starRand.nextFloat() - 0.5f) * 4.0f; // 随机的速度Y
            float size = 1.0f + starRand.nextFloat() * 7.0f; // 随机的大小
            float baseBrightness = 0.5f + starRand.nextFloat() * 0.5f; // 随机的基础亮度
            float blinkSpeed = 0.01f + starRand.nextFloat() * 0.05f; // 随机的闪烁速度
            float baseAlpha = 0.3f + starRand.nextFloat() * 0.7f; // 随机的基础透明度
            int maxLifetime = 100 + starRand.nextInt(200); // 随机的寿命（100-300帧）
            int initialAge = starRand.nextInt(maxLifetime); // 随机的初始年龄
            int rebirthInterval = 300 + starRand.nextInt(300); // 随机的投胎时间间隔（300-600帧）
            
            // 计算星星的颜色（根据用户偏好设置）
            Color color;
            double colorChoice = starRand.nextDouble();
            if (colorChoice < 0.5) {
                // 偏蓝 (R:100-200,G:150-250,B:200-255)
                int red = 100 + starRand.nextInt(101);
                int green = 150 + starRand.nextInt(101);
                int blue = 200 + starRand.nextInt(56);
                color = new Color(red, green, blue);
            } else {
                // 偏紫 (R:150-250,G:100-200,B:200-255)
                int red = 150 + starRand.nextInt(101);
                int green = 100 + starRand.nextInt(101);
                int blue = 200 + starRand.nextInt(56);
                color = new Color(red, green, blue);
            }
            
            // 降低整体亮度以避免刺眼
            color = new Color(
                (int) (color.getRed() * 0.7),
                (int) (color.getGreen() * 0.7),
                (int) (color.getBlue() * 0.7)
            );
            
            // 计算当前周期和年龄
            int cycle = (globalFrameIndex + initialAge) / maxLifetime;
            int age = (globalFrameIndex + initialAge) % maxLifetime;
            
            // 根据投胎时间间隔确定是否处于活跃周期
            boolean isActive = ((globalFrameIndex + initialAge) / rebirthInterval) % 2 == 0;
            
            if (isActive) {
                // 根据初始位置和速度计算当前位置
                double x = startX + velocityX * age;
                double y = startY + velocityY * age;
                
                // 添加一些周期性扰动使运动更自然
                double time = globalFrameIndex * 0.05;
                x += 15 * Math.sin(time * 0.7 + starSeed * 0.001);
                y += 10 * Math.cos(time * 0.5 + starSeed * 0.0015);
                
                // 边界处理 - 当星星移出屏幕时，从另一边出现
                if (x < -size * 4) x = width + size * 4;
                if (x > width + size * 4) x = -size * 4;
                if (y < -size * 4) y = height + size * 4;
                if (y > height + size * 4) y = -size * 4;
                
                // 随着生命周期变化，星星的大小和透明度也会变化
                float lifeRatio = 1.0f - (float) age / maxLifetime;
                float currentSize = size * (0.3f + 0.7f * (float) Math.sin(Math.PI * age / maxLifetime));
                float currentAlpha = baseAlpha * lifeRatio;
                
                // 闪烁效果
                double blinkTime = globalFrameIndex * 0.1;
                float blinkEffect = 0.6f + 0.4f * (float) Math.sin(blinkTime * blinkSpeed * 5 + starSeed * 0.001);
                float currentBrightness = baseBrightness * blinkEffect;
                
                // 星星的核心亮度
                float coreBrightness = currentBrightness * currentAlpha;
                
                // 绘制多层光晕，从内到外逐渐变暗
                // 第一层光晕（最亮）
                float[] fractions1 = {0.0f, 1.0f};
                Color[] colors1 = {
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(120 * coreBrightness)),
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), 0)
                };
                
                RadialGradientPaint gradient1 = new RadialGradientPaint(
                    (float)x, (float)y, currentSize * 2.0f,
                    fractions1, colors1
                );
                
                g2d.setPaint(gradient1);
                g2d.fillOval((int)(x - currentSize * 2.0f), (int)(y - currentSize * 2.0f), (int)(currentSize * 4), (int)(currentSize * 4));
                
                // 第二层光晕（中等亮度）
                float[] fractions2 = {0.0f, 1.0f};
                Color[] colors2 = {
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(80 * coreBrightness)),
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), 0)
                };
                
                RadialGradientPaint gradient2 = new RadialGradientPaint(
                    (float)x, (float)y, currentSize * 4.0f,
                    fractions2, colors2
                );
                
                g2d.setPaint(gradient2);
                g2d.fillOval((int)(x - currentSize * 4.0f), (int)(y - currentSize * 4.0f), (int)(currentSize * 8), (int)(currentSize * 8));
                
                // 第三层光晕（最暗）
                float[] fractions3 = {0.0f, 1.0f};
                Color[] colors3 = {
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), (int)(40 * coreBrightness)),
                    new Color(color.getRed(), color.getGreen(), color.getBlue(), 0)
                };
                
                RadialGradientPaint gradient3 = new RadialGradientPaint(
                    (float)x, (float)y, currentSize * 6.0f,
                    fractions3, colors3
                );
                
                g2d.setPaint(gradient3);
                g2d.fillOval((int)(x - currentSize * 6.0f), (int)(y - currentSize * 6.0f), (int)(currentSize * 12), (int)(currentSize * 12));
                
                // 绘制星星核心（使用更柔和的颜色）
                g2d.setColor(new Color(
                    Math.min(255, color.getRed() + 50),
                    Math.min(255, color.getGreen() + 50),
                    Math.min(255, color.getBlue() + 50),
                    (int)(200 * coreBrightness)
                ));
                g2d.fillOval((int)(x - currentSize * 0.5f), (int)(y - currentSize * 0.5f), (int)(currentSize), (int)(currentSize));
            }
        }
    }
    
    /**
     * 统一的动态星星粒子绘制方法（兼容旧版本）
     * @param g2d Graphics2D对象
     * @param width 视频宽度
     * @param height 视频高度
     * @param frameIndex 帧索引
     * @param random 随机数生成器
     */
    public static void drawStarParticles(Graphics2D g2d, int width, int height, int frameIndex, Random random) {
        drawStarParticles(g2d, width, height, frameIndex, frameIndex, random);
    }
    
    /**
     * 统一的动态星星粒子绘制方法（用于向后兼容）
     * @param g2d Graphics2D对象
     * @param starParticles 星星粒子列表（此参数将被忽略）
     * @param width 视频宽度
     * @param height 视频高度
     * @param frameIndex 帧索引
     * @param globalFrameIndex 全局帧索引（用于分段视频处理）
     * @param random 随机数生成器
     */
    public static void updateAndDrawStarParticles(Graphics2D g2d, List<StarParticle> starParticles, 
            int width, int height, int frameIndex, int globalFrameIndex, Random random) {
        // 忽略starParticles参数，使用基于周期性函数的新实现
        drawStarParticles(g2d, width, height, frameIndex, globalFrameIndex, random);
    }
    
    /**
     * 统一的动态星星粒子绘制方法（兼容旧版本，用于向后兼容）
     * @param g2d Graphics2D对象
     * @param starParticles 星星粒子列表（此参数将被忽略）
     * @param width 视频宽度
     * @param height 视频高度
     * @param frameIndex 帧索引
     * @param random 随机数生成器
     */
    public static void updateAndDrawStarParticles(Graphics2D g2d, List<StarParticle> starParticles, 
            int width, int height, int frameIndex, Random random) {
        updateAndDrawStarParticles(g2d, starParticles, width, height, frameIndex, frameIndex, random);
    }
}